This is a race.
From line 208 to line 221 at
groovy.util.AntBuilder(groovy 1.7.9), System.in is saved and assigned
and then restored without any synchronization:
More details about this bug are at GROOVY-6068
JIRA page.
groovy.util.AntBuilder:
t1 t2 protected void nodeCompleted(final Object parent, final Object node) {
...
1 3 InputStream savedIn = System.in;
InputStream savedProjectInputStream = project.getDefaultInputStream();
if (!(savedIn instanceof DemuxInputStream)) {
project.setDefaultInputStream(savedIn);
2 System.setIn(new DemuxInputStream(project));
}
try {
lastCompletedNode = performTask(task);
} finally {
// restore original streams
project.setDefaultInputStream(savedProjectInputStream);
4 5 System.setIn(savedIn);
}
...
}
a) thread 1 saves its original System.in at 1.
b) thread 1 set its System.in a new DemuxInputStream at 2.
c) context switched, thread 2 saves its original System.in which is the DemuxInputStream in step b)
at 3.
d) context switched , thread 1 restores its orginal System.in
at 4.
e) context switched, thread 2 restores its orignal System.in
which is the new DemuxInputStream in step b) at 5.
f) the new DemuxInputStream in step b) is supposed to be cleared by GC,
but now is referenced by System.in and causes a memory leak.
This bug is reproduced under groovy 1.7.9 and JDK 1.6.0_33.
Execute
the following scripts to run the test to reproduce the bug (assume the
location of the groovy test project is groovy_test_home).
Linux:
${groovy_test_home}/scripts/run6068.sh
[--threadnum arg] [--loops arg]
Windows:
%groovy_test_home%\scripts\run6068.bat
[--threadnum arg] [--loops arg]
The default argument values will be taken if not specified. For
example,
${groovy_test_home}/scripts/run6068.sh
is the same as
${groovy_test_home}/scripts/run6068.sh --threadnum 2 --loops 10
| Option | Function | Default Value | Valid Values |
| --threadnum,-tn | thread number | 2 | integer |
| --loops,-l | loops number | 10 | integer |